package com.ragdollcat.thirdaicodegenerate.aspect;

import com.ragdollcat.thirdaicodegenerate.annotation.CheckLimiterRate;
import com.ragdollcat.thirdaicodegenerate.api.UserAPI;
import com.ragdollcat.thirdaicodegenerate.exception.ErrorCode;
import com.ragdollcat.thirdaicodegenerate.exception.ThrowUtils;
import com.ragdollcat.thirdaicodegenerate.model.entity.User;
import com.ragdollcat.thirdaicodegenerate.util.IpUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.Duration;

/**
 * CheckLimiterRate注解自定义切面
 */
@Component
@Aspect
public class CheckLimiterRateAspect {

    @Resource
    @Lazy
    private UserAPI userService;

    @Resource
    private RedissonClient redissonClient;


    /**
     * 切加入了checkLimiterRate注解的方法
     *
     * @param joinPoint
     * @param checkLimiterRate
     * @throws Throwable
     */
    @Before("@annotation(checkLimiterRate)")
    public void doCheck(JoinPoint joinPoint, CheckLimiterRate checkLimiterRate) throws Throwable {
        String key = generateKeyByType(checkLimiterRate, joinPoint);
        //拿到限流器
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
        //设置一分钟过期
        rateLimiter.expire(Duration.ofHours(1));
        //设置参数
        rateLimiter.trySetRate(RateType.OVERALL, checkLimiterRate.timesInInterval(), checkLimiterRate.interval(), checkLimiterRate.IntervalTimeUnit());
        //尝试获取令牌，获取失败就限流
        ThrowUtils.throwIf(!rateLimiter.tryAcquire(), ErrorCode.TOO_MANY_REQUEST, checkLimiterRate.message());

    }

    /**
     * 根据不同的限流类型，制作key
     *
     * @return
     */
    private String generateKeyByType(CheckLimiterRate checkLimiterRate, JoinPoint joinPoint) {
        String type = checkLimiterRate.type();
        String key = "checkLimiterRate:";
        switch (type) {
            case "user":
                ServletRequestAttributes requestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
                if (requestAttributes != null) {
                    HttpServletRequest request = requestAttributes.getRequest();
                    User user = UserAPI.getLoginUser(request);
                    key = key + user.getId();
                } else {
                    key = key + "default";
                }
                return key;
            case "ip":
                String currentIp = IpUtils.getCurrentIp();
                return key + currentIp;
            case "interfaces":
                MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                Method method = signature.getMethod();
                String declaringClassName = method.getDeclaringClass().getSimpleName();
                String methodName = method.getName();
                return key + declaringClassName + "." + methodName;
        }
        return null;
    }
}
